package com.rarebot.script.randoms;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import com.rarebot.gui.AccountManager;
import com.rarebot.script.Random;
import com.rarebot.script.ScriptManifest;
import com.rarebot.script.methods.Game.Tab;
import com.rarebot.script.wrappers.RSComponent;
import com.rarebot.script.wrappers.RSItem;

@ScriptManifest (authors = {"Anonymau5", "xMunch", "Emeleo"}, version = 2.4, name = "RewardsBox")
public class RewardsBox extends Random {

	private Reward SELECTED_REWARD = null;
	private BufferedImage IMG = null;
	private Point[] XP_POINT = null;

	private interface Values {

		int INTERFACE_MAIN_BOX = 202;
		int INTERFACE_BOX_CONFIRM_BUTTON = 28;
		int INTERFACE_BOX_SELECTION = 15;
		int INTERFACE_BOX_SCROLLBAR = 24;
		int INTERFACE_XP_SELECTION = 1263;
		int INTERFACE_XP_CONFIRM_ID = 42;
		int TICKET_ID = 24154;
		int TICKET_ID2 = 24155;
		int BOX_ID = 14664;
		int BOOK_KNOWLEDGE_ID = 11640;
		int LAMP_ID = 2528;
		int MYSTERY_BOX_ID = 6199;
		int ACTIVATION_ITEMS[] = {BOX_ID, BOOK_KNOWLEDGE_ID, LAMP_ID, MYSTERY_BOX_ID, TICKET_ID, TICKET_ID2};
		Reward DEFAULT_REWARD = Reward.Cash, DEFAULT_XP_REWARD = Reward.Woodcutting;
	}

	private enum Reward {

		Cash, Runes, Coal, Essence, Ore, Bars, Gems,
		Herbs, Seeds, Charms, Surprise, Emote, Costume,
		Attack(13), Defence(27), Strength(20), Constitution(34), Range(21),
		Prayer(28), Magic(14), Cooking(36), Woodcutting(16), Fletching(18),
		Fishing(29), Firemaking(23), Crafting(30), Smithing(22), Mining(15),
		Herblore(24), Agility(17), Thieving(19), Slayer(25), Farming(31),
		Runecrafting(37), Hunter(32), Construction(26), Summoning(33),
		Dungeoneering(35);

		private Reward() {
			this(-1);
		}

		final int XP_SELECTION;

		private Reward(int id) {
			XP_SELECTION = id;
		}

		@Override
		public String toString() {
			return XP_SELECTION != -1 ? "xp item" : super.toString().toLowerCase();
		}

	}

	private enum State {

		OPEN_RANDOM, HANDLE_BOX, HANDLE_XP_REWARD, ERROR
	}

	private State getState() {
		if (interfaces.get(Values.INTERFACE_MAIN_BOX).isValid()) {
			return State.HANDLE_BOX;
		} else if (interfaces.get(Values.INTERFACE_XP_SELECTION).isValid()) {
			return State.HANDLE_XP_REWARD;
		} else if (inventoryContains(Values.ACTIVATION_ITEMS)) {
			return State.OPEN_RANDOM;
		}
		return State.ERROR;
	}

	private RSComponent getRewardInterface(Reward r) {
		RSComponent mainBox = interfaces.getComponent(Values.INTERFACE_MAIN_BOX, Values.INTERFACE_BOX_SELECTION);
		if (mainBox == null) {
			return null;
		}
		RSComponent[] selection = mainBox.getComponents();
		for (int i = 0; i < selection.length; i++) {
			if (selection[i].getText().toLowerCase().contains(r.toString())) {
				return selection[i - 6];
			}
		}
		return null;
	}

	private Color getColorAt(int x, int y) {
		if (IMG == null) {
			DISABLE_PAINT = true;
			sleep(100, 350);
			IMG = env.takeScreenshot(false);
			DISABLE_PAINT = false;
		}
		return new Color(IMG.getRGB(x, y));
	}

	private Point[] getXPPoint(Reward r) {
		ArrayList<Point> points = new ArrayList<Point>();
		final int red = 210;
		if (r.XP_SELECTION != -1 && interfaces.get(Values.INTERFACE_XP_SELECTION).isValid()) {
			Rectangle area = interfaces.getComponent(Values.INTERFACE_XP_SELECTION, r.XP_SELECTION).getArea();
			for (int x = area.x; x < area.width + area.x; x++) {
				for (int y = area.y; y < area.height + area.y; y++) {
					if (getColorAt(x, y).getRed() <= red) {
						points.add(new Point(x, y));
					}
				}
			}
		} else if (interfaces.get(Values.INTERFACE_XP_SELECTION).isValid()) {
			return getXPPoint(Values.DEFAULT_XP_REWARD);
		}
		return points.isEmpty() ? null : points.toArray(new Point[points.size()]);
	}

	private Reward getSelectedReward() {
		String reward = account.getName() == null ? null : AccountManager.getReward(account.getName());
		if (reward != null) {
			for (Reward r : Reward.values()) {
				if (r.name().equalsIgnoreCase(reward) && (interfaces.get(Values.INTERFACE_MAIN_BOX).isValid() ? getRewardInterface(r) != null : true)) {
					return r;
				}
			}
		}
		return Values.DEFAULT_REWARD;
	}

	private boolean scrollTo(Reward r) {
		return interfaces.scrollTo(getRewardInterface(r), interfaces.get(Values.INTERFACE_MAIN_BOX).getComponent(Values.INTERFACE_BOX_SCROLLBAR));
	}

	@Override
	public boolean activateCondition() {
		if (game.isLoggedIn() && !getMyPlayer().isInCombat()) {
			if (bank.isDepositOpen()) {
				return depoBoxContains(Values.ACTIVATION_ITEMS);
			}
			return inventoryContains(Values.ACTIVATION_ITEMS);
		}
		return false;
	}

	public boolean bankIsOpen() {
		return interfaces.get(762).isValid() || interfaces.get(11).isValid();
	}

	public boolean inventoryContains(int... ids) {
		for (RSItem i : inventory.getItems(true)) {
			for (int a : ids) {
				if (i.getID() == a) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean destroyTicket() {
		boolean done = false;
		RSItem ticket = inventory.getItem(Values.TICKET_ID, Values.TICKET_ID2);
		RSComponent destroy = interfaces.getComponent(1183, 3);
		if (ticket != null) {
			if (ticket.interact("Destroy")) {
				sleep(500, 1500);
				if (destroy.isValid()) {
					done = destroy.doClick();
				}
			}
		}
		return done;
	}

	public boolean depoBoxContains(int... ids) {
		RSComponent p = interfaces.getComponent(11, 17);
		for (int k = 0; k < 28; k++) {
			if (p.isValid()) {
				for (int i : ids) {
					if (p.getComponent(k).getComponentID() != -1) {
						return p.getComponent(k).getComponentID() == i;
					}
				}
			}
		}
		return false;
	}

	@Override
	protected int loop() {
		RSComponent ticketText = interfaces.getComponent(1189, 4);
		if (bankIsOpen()) {
			if (bank.close()) {
				return(random(250, 500));
			}
		}
		if (!activateCondition()) {
			return -1;
		}
		if (ticketText != null && ticketText.isValid()) {
			 if (ticketText.getText().contains("must use up an earned")) {
			                log.info("Ticket limit reached; destroying ticket.");
			                if (destroyTicket()) {
			                    return (random(250, 500));
			                }
			            }
			        }
		game.openTab(Tab.INVENTORY, random(0, 5) == 3);
		if (SELECTED_REWARD == null && (interfaces.get(Values.INTERFACE_MAIN_BOX).isValid() || interfaces.get(Values.INTERFACE_XP_SELECTION).isValid())) {
			SELECTED_REWARD = getSelectedReward();
			log.info("Selecting " + SELECTED_REWARD.name() + " as reward");
		}
		switch (getState()) {
		case OPEN_RANDOM:
			RSItem item = inventory.getItem(Values.ACTIVATION_ITEMS);
			return item != null && item.doClick(true) ? random(3000, 3500) : 10;
		case HANDLE_BOX:
			if (SELECTED_REWARD == null) {
				return 100;
			}
			/** validate selected reward*/
			for (final RSComponent child : interfaces.get(137).getComponents()) {
				if (!SELECTED_REWARD.equals(Reward.Emote)) {
					break;
				}
				if (child.containsText("You've already unlocked") && child.containsText("emotes")
						&& !child.containsText("<col=0000ff>")) {
					SELECTED_REWARD = Values.DEFAULT_REWARD;
					break;
				}
			}
			/** scroll to reward interface */
			if (scrollTo(SELECTED_REWARD)) {
				sleep(300, 700);
			}
			RSComponent REWARD_INTERFACE = getRewardInterface(SELECTED_REWARD),
					CONFIRM = interfaces.getComponent(Values.INTERFACE_MAIN_BOX, Values.INTERFACE_BOX_CONFIRM_BUTTON);
			if (REWARD_INTERFACE == null || CONFIRM == null) {
				return 10;
			}
			/** Click reward & Confirm */
			return REWARD_INTERFACE.doClick() && CONFIRM.doClick() ? random(500, 1500) : 10;
		case HANDLE_XP_REWARD:
			if (SELECTED_REWARD == null) {
				return 100;
			}
			if (XP_POINT != null && XP_POINT.length > 0) {
				mouse.click(XP_POINT[random(0, XP_POINT.length)], true);
				sleep(100, 350);
				return interfaces.getComponent(Values.INTERFACE_XP_SELECTION, Values.INTERFACE_XP_CONFIRM_ID).doClick() ? random(1900, 3500) : 10;
			} else {
				XP_POINT = getXPPoint(SELECTED_REWARD);
			}
			return 100;
		case ERROR:
			return 100;
		}
		return -1;
	}

	@Override
	public void onFinish() {
		DISABLE_PAINT = false;
		SELECTED_REWARD = null;
	}

}
